// Copyright by LunaSec (owned by Refinery Labs, Inc)
//
// Licensed under the Business Source License v1.1
// (the "License"); you may not use this file except in compliance with the
// License. You may obtain a copy of the License at
//
// https://github.com/lunasec-io/lunasec/blob/master/licenses/BSL-LunaTrace.txt
//
// See the License for the specific language governing permissions and
// limitations under the License.
package vulnerability

import (
	"fmt"
	"github.com/go-git/go-git/v5"
	"github.com/rs/zerolog/log"
	"io/ioutil"
	"os"
)

type VulnerabilitySource interface {
	// Pull the latest contents of the remote vulnerability source to the provided destination folder.
	Pull(dst string) error
}

func pullVulnerabilitiesFromSource(source, dst string) error {
	switch source {
	case "ghsa":
		_, err := git.PlainClone(dst, false, &git.CloneOptions{
			URL:      "https://github.com/github/advisory-database",
			Progress: os.Stdout,
			Depth:    1,
		})
		return err
	}
	return fmt.Errorf("cannot pull vulnerabilities for source: %s", source)
}

func ensureAdvisoriesExistFromSource(source, advisoryDir string) (string, func(), error) {
	cleanup := func() {}

	if advisoryDir != "" {
		return advisoryDir, cleanup, nil
	}

	advisoryDir, err := ioutil.TempDir("", source+"-advisories")
	if err != nil {
		log.Error().
			Err(err).
			Msg("unable to create temporary directory for advisories")
		return "", cleanup, err
	}
	cleanup = func() {
		err = os.RemoveAll(advisoryDir)
		if err != nil {
			log.Error().
				Err(err).
				Str("advisory dir", advisoryDir).
				Msg("failed to remove temporary advisory location")
		}
	}

	log.Info().
		Str("source", source).
		Msg("pulling advisories from source")

	err = pullVulnerabilitiesFromSource(source, advisoryDir)
	if err != nil {
		log.Error().
			Err(err).
			Msg("unable to pull vulnerabilities from source")
		return "", cleanup, err
	}

	log.Info().
		Str("source", source).
		Msg("collected advisories from source")

	return advisoryDir, cleanup, nil
}
